#include <cstring>
#include <cassert>

#include "array.h"

/*****************************************************
 *  array constructor.                               *
 *  arguments:                                       *
 *  	@size - size of array                        *
 *****************************************************/
array::array(size_t size)
: memory(new int[size]), size(size), capacity(size)
{
	assert(memory != NULL);
}

/*****************************************************
 * array copy constructor.                           *
 * arguments:                                        *
 * 	@obj - array for copying                     *
 *****************************************************/
array::array(const array & obj)
: memory(new int[obj.size]), size(obj.size), capacity(obj.size)
{
	assert(memory != NULL);

	std::copy(obj.memory, obj.memory+obj.size, memory);
}

/*****************************************************
 * swap operation. Used in operator=                 *
 * arguments:                                        *
 * 	@obj - array for swap                        *
 *****************************************************/
void array::swap(array & obj)
{
	std::swap(obj.capacity, capacity);
	std::swap(obj.size, size);
	std::swap(obj.memory, memory);
}

/*****************************************************
 * operator=. Copy, swap and destroy version         *
 * arguments:                                        *
 * 	@obj - copied array                          *
 *****************************************************/
array & array::operator=(array obj)
{
	swap(obj);

	return *this;
}

/*****************************************************
 * stupid little destructor.                         *
 *****************************************************/
array::~array()
{
	delete[] memory;
}

/*****************************************************
 * operator []. Access by position                   *
 * arguments:                                        *
 * 	@pos - value position                        *
 *****************************************************/
int & array::operator[](size_t pos)
{
	assert(pos < size);

	return memory[pos];
}

/*****************************************************
 * const operator[]. Access by number                *
 * arguments:                                        *
 * 	@pos - value position                        *
 * this method is added just for fun, of course, it  *
 * is not needed for int values                      * 
 *****************************************************/
const int & array::operator[](size_t pos) const
{
	assert(pos < size);

	return memory[pos];
}

/*****************************************************
 * riseup. Array riseup routine                      *
 *****************************************************/
void array::riseup()
{
	int * old_memory = memory;
	capacity *= rise_val;

	memory = new int[capacity];
	assert(memory != NULL);

	std::copy(old_memory, old_memory + size, memory);

	delete[] old_memory;
}

/*****************************************************
 * push_back. Add value at end, riseup array if      *
 * needed                                            *
 * arguments:                                        *
 * 	@value - integer value                       *
 *****************************************************/
void array::push_back(int value)
{
	if (capacity == size)
		riseup();

	memory[size++] = value;
}

/*****************************************************
 * set. Set value at specified position              *
 * arguments:                                        *
 * 	@pos - position of element                   *
 * 	@value - new value of element at pos         *
 *****************************************************/
void array::set(size_t pos, int value)
{
	assert(pos < size);

	memory[pos] = value;
}

/*****************************************************
 * get. Access value by number.                      *
 * arguments:                                        *
 * 	@pos - position of element                   *
 *****************************************************/
int array::get(size_t pos) const
{
	assert(pos < size);

	return memory[pos];
}

/*****************************************************
 * get_size. Return array size                       *
 *****************************************************/
size_t array::get_size() const
{
	return size;
}

/*****************************************************
 * print. Output array to ostream                    *
 * arguments:                                        *
 * 	@out - out stream                            *
 *****************************************************/
void array::print(std::ostream & out) const
{
	out << "[";
	for (int i = 0; i < size-1; i++)
		out << memory[i] << ",";

	if (size != 0)
		out << memory[size-1];

	out << "]";
}

/*****************************************************
 * operator<<. Output operator for array             *
 * arguments:                                        *
 * 	@out - out stream                            *
 *	@obj - array for printing                    *
 *****************************************************/
std::ostream & operator<<(std::ostream & out,
	const array & obj)
{
	obj.print(out);

	return out;
}
